package core.impl;

import com.github.houbb.heaven.util.lang.ObjectUtil;
import constant.enums.ScopeEnum;
import core.BeanFactory;
import exception.IocRuntimeException;
import model.BeanDefinition;
import util.util.ArgUtil;
import util.util.ClassUtil;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Max
 * <br>
 * date 2019/12/18 16:09
 * @version 0.1
 */

public class DefaultBeanFactory implements BeanFactory {

    /**
     * bean 身份信息 Map
     * @since 0.1
     */
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    /**
     * bean 实体 Map
     * 只保存 scope 为 singleton 的bean
     * @since 0.1
     */
    private Map<String,Object> beanMap = new ConcurrentHashMap<>();

    /**
     * 类型集合
     */
    private Map<Class,Set<String>> typeBeanNameMap = new ConcurrentHashMap<>();

    /**
     *  注册
     * @param beanName bean 对象名称
     * @param beanDefinition bean的详情
     * @since 0.1
     */
    protected void registerBeanDefinition(final String beanName,BeanDefinition beanDefinition) {
        this.beanDefinitionMap.put(beanName,beanDefinition);


        registerTypeBeanName(beanName,beanDefinition);

        boolean lazyInit = beanDefinition.isLazyInit();
        if(!lazyInit){
            //如果不是懒加载,我们要初始化加载好
            registerLazyBean(beanName,beanDefinition);
        }
    }


    @Override
    public Object getBean(String beanName) {
        ArgUtil.notNull(beanName);

        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(ObjectUtil.isNull(beanDefinition)){
            throw new IocRuntimeException("身份信息未找到");
        }

        String scope = beanDefinition.getScope();
        if(ScopeEnum.PROTOTYPE.getCode().equals(scope)){
            //如果是prototype
            return createBean(beanDefinition);
        } else {
            //如果是singleton
            Object bean = beanMap.get(beanName);
            if(ObjectUtil.isNotNull(bean)) {
                return bean;
            } else {
                Object newBean = createBean(beanDefinition);
                beanMap.put(beanName,newBean);
                return newBean;
            }
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T getBean(String beanName, Class<T> tClass) {
        Object bean = getBean(beanName);
        return (T)bean;
    }

    @Override
    public boolean containsBean(String beanName) {
        ArgUtil.notNull(beanName);
        return beanDefinitionMap.containsKey(beanName);
    }

    @Override
    public boolean isTypeMatch(String beanName, Class requiredType) {
        ArgUtil.notNull(beanName);
        ArgUtil.notNull(requiredType);
        return getBean(beanName).getClass()==requiredType;
    }

    //    --------------------middle------------------------------------

    /**
     * 根据class 获取 对应类型的
     * @param clazz class
     * @return set
     */
    protected Set<String> getBeanNames(Class clazz){
        return typeBeanNameMap.get(clazz);
    }

//-------------------------private-------------------------------------

    /**
     *
     * @param beanDefinition 对象信息
     * @return 对象实例
     * @since 0.1
     */
    private Object createBean(BeanDefinition beanDefinition){
        String className = beanDefinition.getClassName();
        Class clazz = ClassUtil.getClass(className);
        return ClassUtil.newInstance(clazz);
    }

    /**
     * 分为 初始化  typeBeanNameMap
     * @param beanName beanName
     * @param beanDefinition beanDefinition
     * @since 0.4
     */
    private void registerTypeBeanName(String beanName,BeanDefinition beanDefinition){
        //@since 0.2
        //初始化生成typeBeanNameMap
        String clazz = beanDefinition.getClassName();
        Class aClass = ClassUtil.getClass(clazz);
        Set<String> classNameSet = typeBeanNameMap.get(aClass);
        if(ObjectUtil.isNull(classNameSet)){
            classNameSet = new HashSet<>();
        }
        classNameSet.add(beanName);
        typeBeanNameMap.put(aClass, classNameSet);
    }

    private void registerLazyBean(String beanName,BeanDefinition beanDefinition) {
        System.out.println("不是懒加载 我们要在初始化时加载好："+beanName);
        Object bean = createBean(beanDefinition);
        beanMap.put(beanName,bean);
    }
}
